use std::sync::Arc;

use anyhow::{anyhow, Result};
use sea_orm::{DatabaseConnection, EntityTrait};
use tracing::info;

use crate::dto::system_dto::PrjSystemDto;
use crate::entity::prelude::{CfgVarsystem, PrjSystem};
use crate::entity::prj_system::Model;
use crate::repo::point_repo::DbContextHolder;

pub struct SystemRepo {
    db_contexts: Arc<Vec<DatabaseConnection>>,
}

impl DbContextHolder for SystemRepo {
    fn get_db_contexts(&self) -> &Vec<DatabaseConnection> {
        &self.db_contexts
    }
}
impl SystemRepo {
    pub fn new(dbs: Arc<Vec<DatabaseConnection>>) -> Self {
        Self { db_contexts: dbs }
    }

    pub async fn get_tree(&self, machine_index: u32) -> Result<Vec<PrjSystemDto>> {
        let db_context = self.get_db_context(machine_index);
        let result = PrjSystem::find()
            .find_with_related(CfgVarsystem)
            .all(db_context).await.map_err(|e| anyhow!("查询系统树失败：{}", e))?
            ;
        // 将 model, 和 vec<cfg_varsystem::model 分别存入一个 vec 中
        let mut system_list = Vec::new();
        let mut point_list = Vec::new();
        for (system, point) in &result {
            system_list.push(system.clone());
            point_list.push(point.clone());
        }
        // system_list  根据 parent_id 递归 拼接树
        let mut tree = Vec::new();
        for system in &system_list {
            if system.parent_id.is_none() || system.parent_id ==Some(0) {
                let children = find_children(&system_list, system.id);
                tree.push(PrjSystemDto::from_model(system.clone(), children, Vec::new()));
            }
        }
        Ok(tree)
    }

    pub async fn get_by_id(&self, machine_index: u32, id: i32) -> Result<PrjSystemDto> {
        let db_context = self.get_db_context(machine_index);
        // 查询单个
        let result = PrjSystem::find_by_id(id)
            .find_with_related(CfgVarsystem)
            .all(db_context).await.map_err(|e| anyhow!("查询系统失败：{}", e))?
            ;
        if result.len() == 0 {
            return Err(anyhow!("未找到系统"));
        }
        let (system, point) = &result[0];
        // map to dto
        let dto = PrjSystemDto::from_model(system.clone(), Vec::new(), point.clone());
        Ok(dto)
    }
}

fn find_children(system_list: &Vec<Model>, parent_id: i32) -> Vec<PrjSystemDto> {
    let mut children = Vec::new();
    for system in system_list {
        if system.parent_id.is_some() && system.parent_id.unwrap() == parent_id {
            let system_children = find_children(system_list, system.id);
            children.push(PrjSystemDto::from_model(system.clone(), system_children, Vec::new()));
        }
    }
    children
}
